<template>
  <div class="webglPrc2">
     <!-- <canvas>标记提供webgl绘制区域 -->
    <canvas ref="myGLCanvas" :width="rect?.width" :height="rect?.height"/>
  </div>
</template>

<script lang="ts">
import { Vue, Options } from 'vue-property-decorator';
// import  from 'webgl-debug'
@Options({ components: {} })
export default class DomApiPrc extends Vue {
  public rect: DOMRect|null = null;
  public gl!: WebGLRenderingContext;
  public shaderProgram: WebGLProgram|null=null;
  public hexagonVertexBuffer: WebGLBuffer|null = null;
  public triangleVertexBuffer: WebGLBuffer|null = null;
  public triangleVertexColorBuffer: WebGLBuffer|null = null;
  public stripVertexBuffer: WebGLBuffer|null = null;
  public stripElementBuffer: WebGLBuffer|null = null;
  public vertexPositionAttribute=0;
  public vertexColorAttribute=0;
  public buffer: ArrayBuffer|null=null;
  public positionView: Float32Array|null = null;
  public colorView: Uint8Array|null = null;

  public draw() {
    this.gl.viewport(0, 0, this.rect!.width, this.rect!.height);// 定义一个视口
    this.gl.clear(this.gl.COLOR_BUFFER_BIT);// 通过参数this.gl.COLOR_BUFFER_BIT把颜色缓冲清除为事先用 this.gl.clearColor()定义的颜色

    // 绘制六边形
    this.gl.disableVertexAttribArray(this.vertexColorAttribute);// 禁用属性，使用常量；不禁用使用数组变量
    this.gl.vertexAttrib4f(this.vertexColorAttribute, 0.0, 0.0, 0.0, 1.0);// 设置禁用属性常量值
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.hexagonVertexBuffer);
    // 告诉显卡从当前绑定的缓冲区（bindBuffer指定的缓冲区）中读取顶点数据
    this.gl.vertexAttribPointer(this.vertexPositionAttribute, 3, this.gl.FLOAT, false, 0, 0);
    this.gl.drawArrays(this.gl.LINE_STRIP, 0, 7); // 用于从向量数组中绘制图元 gl.drawArrays(mode, first, count);

    // 绘制独立三角形
    this.gl.enableVertexAttribArray(this.vertexColorAttribute);
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.triangleVertexBuffer);
    this.gl.vertexAttribPointer(this.vertexPositionAttribute, 3, this.gl.FLOAT, false, 0, 0);
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.triangleVertexColorBuffer);
    this.gl.vertexAttribPointer(this.vertexColorAttribute, 4, this.gl.FLOAT, false, 0, 0);
    this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);

    // 绘制三角带
    this.gl.disableVertexAttribArray(this.vertexColorAttribute);
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.stripVertexBuffer);
    this.gl.vertexAttribPointer(this.vertexPositionAttribute, 3, this.gl.FLOAT, false, 0, 0);
    this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.stripElementBuffer);
    this.gl.vertexAttrib4f(this.vertexColorAttribute, 1.0, 1.0, 0.0, 1.0);
    this.gl.drawElements(this.gl.TRIANGLE_STRIP, 25, this.gl.UNSIGNED_SHORT, 0);
    // 绘制辅助线
    this.gl.vertexAttrib4f(this.vertexColorAttribute, 0.0, 0.0, 0.0, 1.0);
    this.gl.drawArrays(this.gl.LINE_STRIP, 0, 11);
    this.gl.drawArrays(this.gl.LINE_STRIP, 11, 11);

    requestAnimationFrame(() => {
      this.draw();
    });
    // requestAnimationFrame(this.startUp.bind(this));
    // 错误写法
    // requestAnimationFrame(this.startUp);
  }
  // 3.建立缓冲，用来保存顶点数据
  public setupBuffers() {
    // 六边形的顶点位置
    this.hexagonVertexBuffer = this.gl.createBuffer(); // 创建并初始化一个用于储存顶点数据或着色数据的WebGLBuffer对象
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.hexagonVertexBuffer);// 把新建的WebGLBuffer对象绑定为当前的数组缓冲对象
    const hexagonVertices = [
      -0.3, 0.6, 0.0,
      -0.4, 0.8, 0.0,
      -0.6, 0.8, 0.0,
      -0.7, 0.6, 0.0,
      -0.6, 0.4, 0.0,
      -0.4, 0.4, 0.0,
      -0.3, 0.6, 0.0,
    ];
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(hexagonVertices), this.gl.STATIC_DRAW);

    // 独立三角形的顶点位置
    this.triangleVertexBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.triangleVertexBuffer);
    const triangleVertices = [
      0.3, 0.4, 0.0,
      0.7, 0.4, 0.0,
      0.5, 0.8, 0.0,
    ];
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(triangleVertices), this.gl.STATIC_DRAW);

    // 独立三角形的顶点颜色
    this.triangleVertexColorBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.triangleVertexColorBuffer);
    const colors = [
      1.0, 0.0, 0.0, 1.0,
      0.0, 1.0, 0.0, 1.0,
      0.0, 0.0, 1.0, 1.0,
    ];
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(colors), this.gl.STATIC_DRAW);

    // 三角带的顶点位置
    this.stripVertexBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.stripVertexBuffer);
    const stripVertices = [
      -0.5, 0.2, 0.0,
      -0.4, 0.0, 0.0,
      -0.3, 0.2, 0.0,
      -0.2, 0.0, 0.0,
      -0.1, 0.2, 0.0,
      0.0, 0.0, 0.0,
      0.1, 0.2, 0.0,
      0.2, 0.0, 0.0,
      0.3, 0.2, 0.0,
      0.4, 0.0, 0.0,
      0.5, 0.2, 0.0,
      -0.5, -0.3, 0.0,
      -0.4, -0.5, 0.0,
      -0.3, -0.3, 0.0,
      -0.2, -0.5, 0.0,
      -0.1, -0.3, 0.0,
      0.0, -0.5, 0.0,
      0.1, -0.3, 0.0,
      0.2, -0.5, 0.0,
      0.3, -0.3, 0.0,
      0.4, -0.5, 0.0,
      0.5, -0.3, 0.0,
    ];
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(stripVertices), this.gl.STATIC_DRAW);

    // 三角带的元素数组缓冲
    this.stripElementBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.stripElementBuffer);
    const indices = [
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      10, 10, 11,
      11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
    ];
    this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW);
    this.gl.enableVertexAttribArray(this.vertexPositionAttribute);
    this.gl.enableVertexAttribArray(this.vertexColorAttribute);
  }
  public setupShaders() {
    // 1.创建着色器
    // 编写着色器源代码
    const vertexShaderSource = `precision mediump float;
                                attribute vec3 aVertexPosition;
                                attribute vec4 aVertexColor;
                                varying vec4 vColor;
                                void main(){
                                  vColor = aVertexColor;
                                  gl_Position = vec4(aVertexPosition,1.0);
                                }`;
    // gl_Position放置顶点坐标信息
    const fragmentShaderSource = `precision mediump float;
                                  varying vec4 vColor;
                                  void main(){
                                    gl_FragColor = vColor;
                                  }`;
    // gl_FragColor设置当前片点的颜色

    // 根据源代码创建着色器
    const vertexShader = this.loadShader(this.gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = this.loadShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
    // 2.创建程序对象和链接着色器
    // createProgram()创建和初始化一个 WebGLProgram 对象。一个 WebGLProgram 对象由两个编译过后的 WebGLShader 组成 - 顶点着色器和片段着色器
    this.shaderProgram = this.gl.createProgram();
    // attachShader()负责往 WebGLProgram 添加一个片段或者顶点着色器。
    this.gl.attachShader(this.shaderProgram!, vertexShader!);
    this.gl.attachShader(this.shaderProgram!, fragmentShader!);
    // inkProgram()方法链接给定的WebGLProgram，从而完成为程序的片元和顶点着色器准备GPU代码的过程。
    this.gl.linkProgram(this.shaderProgram!);
    if (!this.gl.getProgramParameter(this.shaderProgram!, this.gl.LINK_STATUS)) {
      alert('Failed to setup shaders');
    }
    this.gl.useProgram(this.shaderProgram!);// 告诉webgl引擎可以用这个程序对象绘制图像
    // getAttribLocation() 方法返回了给定WebGLProgram对象中某属性的下标指向位置。 把顶点着色器使用的属性绑定到通用属性索引上
    // 返回值：表明属性位置的下标数字，如果找不到该属性则返回-1。
    this.vertexPositionAttribute = this.gl.getAttribLocation(this.shaderProgram!, 'aVertexPosition');
    this.vertexColorAttribute = this.gl.getAttribLocation(this.shaderProgram!, 'aVertexColor');
  }
  // 1.创建一个可以载入到GPU并且能够绘制几何图形的WebGL着色器
  public loadShader(type: number, shaderSource: any) {  // type 类型应该是什么
    const shader = this.gl.createShader(type);// 创建一个WebGLShader着色器对象
    this.gl.shaderSource(shader!, shaderSource);// 挂载GLSL源代码
    this.gl.compileShader(shader!);// 完成着色器的编译

    // 检查编译的状态，如果出现错误，发出警告消息，并删除着色器对象
    if (!this.gl.getShaderParameter(shader!, this.gl.COMPILE_STATUS)) {
      alert(`Error Compiling shader${this.gl.getShaderInfoLog(shader!)}`);
      this.gl.deleteShader(shader);
      return null;
    }
    return shader;
  }
  public mounted() {
    // Element.getBoundingClientRect()的返回值是一个DOMRect对象
    this.rect = (this.$el as HTMLDivElement).getBoundingClientRect();
    this.gl = (this.$refs.myGLCanvas as HTMLCanvasElement).getContext('webgl') as WebGLRenderingContext;
    this.setupShaders();
    this.setupBuffers();
    this.gl.clearColor(1, 1, 1, 1); // 用于设置清空颜色缓冲时的颜色值

    this.gl.frontFace(this.gl.CCW);// 告诉webgl采用逆时针组绕的三角形是正面三角形 默认正面三角形
    this.gl.enable(this.gl.CULL_FACE);// 让webgl开启某种特性 gl.CULL_FACE	激活多边形正反面剔除.
    this.gl.cullFace(this.gl.BACK);// 指定适合进行剔除的面是正面还是背面 默认背面

    this.draw();
  }
}
</script>

<style lang="postcss" scoped>
.webglPrc2{
    /* 为什么不加定位 就不会在页面显示 */
    touch-action: none;
    position: absolute;
    left: 0;top: 0;
    width: 100%;
    height: 100%;
    background-color: grey;
}
</style>
